package com.example.deepschool.util;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Arrays;
import java.util.Objects;

@Component
public class Redis {
	public static StringRedisTemplate stringRedisTemplate;
	
	public Redis ( StringRedisTemplate stringRedisTemplate ) {
		Redis.stringRedisTemplate = stringRedisTemplate;
	}
	
	/**
	 * 删除指定的Redis键。
	 *
	 * @param key 要删除的键。
	 */
	public static void DEL ( String key ) {
		stringRedisTemplate.delete( key );
	}
	
	/**
	 * 检查指定键是否存在。
	 *
	 * @param key 要检查的键。
	 * @return 键存在返回true，否则返回false。
	 */
	public static boolean EXISTS ( String key ) {
		return Boolean.TRUE.equals( stringRedisTemplate.hasKey( key ) );
	}
	
	/**
	 * 为指定键设置过期时间。
	 *
	 * @param key     要设置过期时间的键。
	 * @param seconds 过期时间（秒）。
	 */
	public static void EXPIRE (String key, long seconds) {
		stringRedisTemplate.expire( key, Duration.ofSeconds( seconds ) );
	}
	
	/**
	 * 根据模式匹配搜索键。
	 *
	 * @param pattern 模式。
	 * @return 匹配的键数组。
	 */
	public static String[] KEYS ( String pattern ) {
		return Objects.requireNonNull( stringRedisTemplate.keys( pattern ) ).toArray( new String[0] );
	}
	
	/**
	 * 设置指定键的值。
	 *
	 * @param key   要设置的键。
	 * @param value 要设置的值。
	 */
	public static void SET ( String key, String value ) {
		stringRedisTemplate.opsForValue( ).set( key, value );
	}
	
	/**
	 * 设置指定键的值，并设定过期时间。
	 *
	 * @param key     要设置的键。
	 * @param value   要设置的值。
	 * @param seconds 过期时间（秒）。
	 */
	public static void SET ( String key, String value, int seconds ) {
		stringRedisTemplate.opsForValue( ).set( key, value );
		stringRedisTemplate.expire( key, Duration.ofSeconds( seconds ) );
	}
	
	/**
	 * 获取指定键的值。
	 *
	 * @param key 要获取值的键。
	 * @return 键对应的值。
	 */
	public static String GET ( String key ) {
		return stringRedisTemplate.opsForValue( ).get( key );
	}
	
	/**
	 * 获取多个键的值。
	 *
	 * @param keys 要获取值的键数组。
	 * @return 键对应的值数组。
	 */
	public static String[] MGET ( String[] keys ) {
		return Objects.requireNonNull( stringRedisTemplate.opsForValue( ).multiGet( Arrays.asList( keys ) ) ).toArray( new String[0] );
	}
	
	/**
	 * 同时设置多个键的值。
	 *
	 * @param keys   要设置的键数组。
	 * @param values 要设置的值数组。
	 */
	public static void MSET ( String[] keys, String[] values ) {
		for ( int i = 0; i < keys.length; i++ ) {
			stringRedisTemplate.opsForValue( ).set( keys[i], values[i] );
		}
	}
	
	/**
	 * 增加指定键的值。
	 *
	 * @param key 要增加值的键。
	 */
	public static void INCR ( String key ) {
		stringRedisTemplate.opsForValue( ).increment( key );
	}
	
	/**
	 * 减少指定键的值。
	 *
	 * @param key 要减少值的键。
	 */
	public static void DECR ( String key ) {
		stringRedisTemplate.opsForValue( ).decrement( key );
	}
	
	/**
	 * 为指定键增加指定数值。
	 *
	 * @param key   要增加值的键。
	 * @param value 要增加的数值。
	 */
	public static void INCRBY ( String key, int value ) {
		stringRedisTemplate.opsForValue( ).increment( key, value );
	}
	
	/**
	 * 为指定键减少指定数值。
	 *
	 * @param key   要减少值的键。
	 * @param value 要减少的数值。
	 */
	public static void DECRBY ( String key, int value ) {
		stringRedisTemplate.opsForValue( ).decrement( key, value );
	}
	
	/**
	 * 删除哈希表中指定字段。
	 *
	 * @param key   哈希表的键。
	 * @param field 要删除的字段。
	 */
	public static void HDEL ( String key, String field ) {
		stringRedisTemplate.opsForHash( ).delete( key, field );
	}
	
	/**
	 * 为哈希表的指定字段设置值。
	 *
	 * @param key   哈希表的键。
	 * @param field 字段。
	 * @param value 值。
	 */
	public static void HSET ( String key, String field, String value ) {
		stringRedisTemplate.opsForHash( ).put( key, field, value );
	}
	
	/**
	 * 为哈希表的指定字段设置值，并设定过期时间。
	 *
	 * @param key     哈希表的键。
	 * @param field   字段。
	 * @param value   值。
	 * @param seconds 过期时间（秒）。
	 */
	public static void HSET ( String key, String field, String value, int seconds ) {
		stringRedisTemplate.opsForHash( ).put( key, field, value );
		stringRedisTemplate.expire( key, Duration.ofSeconds( seconds ) );
	}
	
	/**
	 * 同时为哈希表的多个字段设置值。
	 *
	 * @param key    哈希表的键。
	 * @param fields 字段数组。
	 * @param values 值数组。
	 */
	public static void HMSET ( String key, String[] fields, String[] values ) {
		for ( int i = 0; i < fields.length; i++ ) {
			stringRedisTemplate.opsForHash( ).put( key, fields[i], values[i] );
		}
	}
	
	/**
	 * 检查哈希表中指定字段是否存在。
	 *
	 * @param key   哈希表的键。
	 * @param field 字段。
	 * @return 字段存在返回true，否则返回false。
	 */
	public static boolean HEXISTS ( String key, String field ) {
		return Boolean.TRUE.equals( stringRedisTemplate.opsForHash( ).hasKey( key, field ) );
	}
	
	/**
	 * 获取哈希表中指定字段的值。
	 *
	 * @param key   哈希表的键。
	 * @param field 字段。
	 * @return 字段的值。
	 */
	public static String HGET ( String key, String field ) {
		return ( String ) stringRedisTemplate.opsForHash( ).get( key, field );
	}
	
	/**
	 * 获取哈希表中所有字段和值。
	 *
	 * @param key 哈希表的键。
	 * @return 包含所有字段和值的数组。
	 */
	public static String[] HGETALL ( String key ) {
		return Objects.requireNonNull( stringRedisTemplate.opsForHash( ).entries( key ) ).values( ).toArray( new String[0] );
	}
	
	/**
	 * 获取哈希表中的所有字段。
	 *
	 * @param key 哈希表的键。
	 * @return 包含所有字段的数组。
	 */
	public static String[] HKEYS ( String key ) {
		return Objects.requireNonNull( stringRedisTemplate.opsForHash( ).keys( key ) ).toArray( new String[0] );
	}
	
	/**
	 * 获取哈希表中的所有值。
	 *
	 * @param key 哈希表的键。
	 * @return 包含所有值的数组。
	 */
	public static String[] HVALS ( String key ) {
		return Objects.requireNonNull( stringRedisTemplate.opsForHash( ).values( key ) ).toArray( new String[0] );
	}
	
	/**
	 * 在列表的头部插入值。
	 *
	 * @param key   列表的键。
	 * @param value 要插入的值。
	 * @return 插入后的列表长度。
	 */
	public static Long LPUSH ( String key, String value ) {
		return stringRedisTemplate.opsForList( ).leftPush( key, value );
	}
	
	/**
	 * 在列表的头部插入多个值。
	 *
	 * @param key    列表的键。
	 * @param values 要插入的值数组。
	 * @return 插入后的列表长度。
	 */
	public static Long LMPUSH ( String key, String[] values ) {
		return stringRedisTemplate.opsForList( ).leftPushAll( key, values );
	}
	
	/**
	 * 在列表的尾部插入值。
	 *
	 * @param key   列表的键。
	 * @param value 要插入的值。
	 * @return 插入后的列表长度。
	 */
	public static Long RPUSH (String key, String value) {
		return stringRedisTemplate.opsForList().rightPush(key, value);
	}
	
	/**
	 * 获取列表的长度。
	 *
	 * @param key 列表的键。
	 * @return 列表的长度。
	 */
	public static Long LLEN ( String key ) {
		return stringRedisTemplate.opsForList( ).size( key );
	}
	
	/**
	 * 获取列表指定索引的值。
	 *
	 * @param key   列表的键。
	 * @param index 索引。
	 * @return 索引对应的值。
	 */
	public static String LINDEX ( String key, int index ) {
		return stringRedisTemplate.opsForList( ).index( key, index );
	}
	
	/**
	 * 设置列表指定索引的值。
	 *
	 * @param key   列表的键。
	 * @param index 索引。
	 * @param value 要设置的值。
	 */
	public static void LSET ( String key, int index, String value ) {
		stringRedisTemplate.opsForList( ).set( key, index, value );
	}
	
	/**
	 * 根据数量删除列表头部或尾部的元素。
	 *
	 * @param key   列表的键。
	 * @param count 删除数量，负数表示从尾部删除。
	 * @param value 要删除的值。
	 */
	public static void LREM ( String key, int count, String value ) {
		stringRedisTemplate.opsForList( ).remove( key, count, value );
	}
	
	/**
	 * 从列表头部弹出一个元素。
	 *
	 * @param key 列表的键。
	 * @return 弹出的元素。
	 */
	public static String LPOP ( String key ) {
		return stringRedisTemplate.opsForList( ).leftPop( key );
	}
	
	/**
	 * 从列表尾部弹出一个元素。
	 *
	 * @param key 列表的键。
	 * @return 弹出的元素。
	 */
	public static String RPOP ( String key ) {
		return stringRedisTemplate.opsForList( ).rightPop( key );
	}
	
	/**
	 * 向指定的集合中添加一个元素。
	 *
	 * @param key   集合的键。
	 * @param value 要添加的元素。
	 * @return 如果元素被成功添加，返回1；如果元素已存在，返回0。
	 */
	public static Long SADD ( String key, String value ) {
		return stringRedisTemplate.opsForSet( ).add( key, value );
	}
	
	/**
	 * 向指定的集合中添加多个元素。
	 *
	 * @param key    集合的键。
	 * @param values 要添加的多个元素。
	 * @return 成功添加的新元素的数量。
	 */
	public static Long SADD ( String key, String[] values ) {
		return stringRedisTemplate.opsForSet( ).add( key, values );
	}
	
	/**
	 * 获取集合的成员数量。
	 *
	 * @param key 集合的键。
	 * @return 集合的成员数量。
	 */
	public static Long SCARD ( String key ) {
		return stringRedisTemplate.opsForSet( ).size( key );
	}
	
	/**
	 * 计算多个集合的差集。
	 *
	 * @param keys 多个集合的键。
	 * @return 返回这些集合的差集。
	 */
	public static String[] SDIFF ( String[] keys ) {
		return Objects.requireNonNull( stringRedisTemplate.opsForSet( ).difference( Arrays.asList( keys ) ) ).toArray( new String[0] );
	}
	
	/**
	 * 计算多个集合的交集。
	 *
	 * @param keys 多个集合的键。
	 * @return 返回这些集合的交集。
	 */
	public static String[] SINTER ( String[] keys ) {
		return Objects.requireNonNull( stringRedisTemplate.opsForSet( ).intersect( Arrays.asList( keys ) ) ).toArray( new String[0] );
	}
	
	/**
	 * 检查一个元素是否为集合的成员。
	 *
	 * @param key   集合的键。
	 * @param value 要检查的元素。
	 * @return 如果元素是集合的成员，返回true；否则返回false。
	 */
	public static boolean SISMEMBER ( String key, String value ) {
		return Boolean.TRUE.equals( stringRedisTemplate.opsForSet( ).isMember( key, value ) );
	}
	
	/**
	 * 获取集合的所有成员。
	 *
	 * @param key 集合的键。
	 * @return 返回集合的所有成员。
	 */
	public static String[] SMEMBERS ( String key ) {
		return Objects.requireNonNull( stringRedisTemplate.opsForSet( ).members( key ) ).toArray( new String[0] );
	}
	
	/**
	 * 从集合中移除一个元素。
	 *
	 * @param key   集合的键。
	 * @param value 要移除的元素。
	 * @return 如果成功移除元素，返回1；如果元素不存在于集合中，返回0。
	 */
	public static Long SREM ( String key, String value ) {
		return stringRedisTemplate.opsForSet( ).remove( key, value );
	}
	
	/**
	 * 计算多个集合的并集。
	 *
	 * @param keys 多个集合的键。
	 * @return 返回这些集合的并集。
	 */
	public static String[] SUNION ( String[] keys ) {
		return Objects.requireNonNull( stringRedisTemplate.opsForSet( ).union( Arrays.asList( keys ) ) ).toArray( new String[0] );
	}
	
}
